#ifndef JSON_H__
#define JSON_H__

#include <variant>
#include <string>
#include <vector>
#include <exception>
#include <stdexcept>
#include <sstream>
#include <map>

#include "parser.h"

namespace Asukai
{
    namespace json
    {
        class Parser;

        class Json
        {
        public:
            enum class Type
            {
                json_null = 0,
                json_bool,
                json_int,
                json_double,
                json_string,
                json_array,
                json_object
            };

            using iterator = std::vector<Json>::iterator;

            Json();
            Json(bool value);
            Json(int value);
            Json(double value);
            Json(std::vector<Json> value);
            Json(const char *value);
            Json(const std::string &value);
            Json(Type type);
            Json(const Json &other);
            // Json(std::map<std::string, Json> value);

            operator bool();
            operator int();
            operator double();
            operator std::string();

            Json &operator[](size_t index);
            void append(const Json &other);

            Json &operator[](const std::string &key);
            Json &operator[](const char *key);
            // void append(std::pair<std::string, Json> pair);

            std::string str() const;

            iterator begin()
            {
                return std::get<std::vector<Json>>(m_value).begin();
            }
            iterator end()
            {
                return std::get<std::vector<Json>>(m_value).end();
            }

            bool operator==(const Json &other) const;
            bool operator!=(const Json &other) const;

            bool isNull() const { return m_type == Type::json_null; }
            bool isBool() const { return m_type == Type::json_bool; }
            bool isInt() const { return m_type == Type::json_int; }
            bool isDoube() const { return m_type == Type::json_double; }
            bool isSrting() const { return m_type == Type::json_string; }
            bool isArray() const { return m_type == Type::json_array; }
            bool isObject() const { return m_type == Type::json_object; }

            bool asBool() const;
            int asInt() const;
            double asDouble() const;
            std::string asString() const;
            // std::vector<Json> asAray() const;
            // std::map<std::string, Json> asObject() const;

            bool has(size_t index);
            bool has(const char* key);
            bool has(const std::string& key);

            void remove(size_t index);
            void remove(const char* key);
            void remove(const std::string& key);

            void parse(const std::string& str);


        private:
            using Value = std::variant<std::monostate, bool, int, double, std::string, std::vector<Json>, std::map<std::string, Json>>;

            Type m_type;
            Value m_value;
        };
    }
}

#endif